package ann;

import java.util.ArrayList;
import java.util.List;

public class SubNetwork extends Module{
	
	//private boolean learningIsEnabled;
	//private boolean isActive;
	//private int maxSettlingRounds;
	List<Module> submodules;

	public SubNetwork()
	{
		super();
		submodules = new ArrayList<Module>();
	}
	
	public void setInput(int i, double j){
		assert submodules.size()>0;
		submodules.get(0).setInput(i, j);
	}

	public void addSubModule(Module subModule) {
		if(subModule.getBiasLayer()!=null)
			addSubModule(subModule.getBiasLayer());
		submodules.add(subModule);
		subModule.setParent(this);
	}

	public int getInputSize() {
		if(submodules.size()==0)
			return 0;
		return submodules.get(0).getInputSize();
	}

	public int getOutputSize() {
		if(submodules.size()==0)
			return 0;
		return submodules.get(submodules.size()-1).getOutputSize();
	}

	public Module getFirstSubModule() {
		if(submodules.size()==0)
			return null;
		return submodules.get(0);
	}
	
	public Module getLastSubModule() {
		if(submodules.size()==0)
			return null;
		return submodules.get(submodules.size()-1);
	}

	public void updateInput() {
		List<Link> totalInputLinks = super.getTotalInputLinks();
		
		for(int i  = 0; i<getInputSize();i++)
			setInput(i, 0.0);
		
		for(Link link: totalInputLinks)
		{
			Module fromModule = link.getFromModule();
			for(Arc arc: link)
			{
				incrementInput(arc.getToIndex(),fromModule.getOutput(arc.getFromIndex())*arc.getWeight());
			}
		}
	}

	public void incrementInput(int i, double j) {
		assert submodules.size()>0;
		submodules.get(0).incrementInput(i, j);
	}

	public double getOutput(int index) {
		assert submodules.size()>0;
		return submodules.get(submodules.size()-1).getOutput(index);
	}
	
	public void setTarget(int index, double target) {
		assert submodules.size()>0;
		submodules.get(submodules.size()-1).setTarget(index,target);
	}
	
	public String toString()
	{
		String ret="";
		for(Module mod:submodules)
		{
			ret+=mod.toString();
			for(Link link : mod.getInputLinks())
			{
				ret+=link.toString();
			}
		}
		return ret;
	}

	public void updateOutput() {
		assert submodules.size()>0;
		
		submodules.get(0).updateOutput();
		
		for(int i = 1; i<submodules.size();i++)
		{
			
			submodules.get(i).updateInput();
			submodules.get(i).updateOutput();
		}
	}

	public void propagateError() {
		for(Module subModule : submodules)
			subModule.clearInError();
		
		assert(submodules.size()>0);
		
		submodules.get(submodules.size()-1).propagateError();
		
		for(int i = submodules.size()-2; i>=0;i-- )
		{
			submodules.get(i).updateOutError();
			submodules.get(i).propagateError();
		}
	}

	
	public void clearInError() {
		assert submodules.size()>0;
		submodules.get(0).clearInError();
	}
	
	public void updateOutError() {
		assert(false):"not implemented";
	}

	public double getInError(int index) {
		assert submodules.size()>0;
		return submodules.get(0).getInError(index);
	}

	public void incrementOutError(int index, double increment) {
		assert submodules.size()>0;
		submodules.get(submodules.size()-1).incrementOutError(index, increment);
	}

	public void incrementWeightDeltas() {
		for(Module module : submodules)
		{
			for(Link link : module.getInputLinks())
			{
				link.incrementWeightDeltas();
			}
		}
	}

	public void addWeightDeltas() {
		for(Module module : submodules)
		{
			for(Link link : module.getInputLinks())
			{
				link.addWeightDeltas();
			}
		}
	}

	public Module getFirstLayer() {
		return getFirstSubModule().getFirstLayer();
	}

	public Module getLastLayer() {
		return getLastSubModule().getLastLayer();
	}
}
